import type { Ref } from "vue";
import type { HandleType, IDraggable, MouseRecord } from "../core/types";
import { DomUtils } from "./DomUtils";
import { MathUtils } from "./MathUtils";
import { MatrixUtils } from "./MatrixUtils";

export class OBB {
  /* --------------拖拽逻辑------------- */
  /**
   * @description 拖拽的点实际仅有四个方向
   * 核心拖拽逻辑仅有四个方向
   * 对角线的拖拽是临边拖拽的组合
   * 如拖拽右下角，实际是拖拽右侧和底部
   *  */
  static isDragSizeOutBoundary(param: {
    rect: IDraggable;
    mouseRecord: MouseRecord;
    key: HandleType;
    dx: number;
    dy: number;
    el: HTMLElement | null;
  }) {
    const { rect, dx, mouseRecord, dy, key } = param;
    const { sw, sh, sx, sy } = mouseRecord;
    const { minWidth, rotate, maxWidth, grid, minHeight, maxHeight, lockAspectRatio, w, h } = rect;
    const [gx, gy] = grid;
    const cos = MathUtils.cos(rotate);
    const sin = MathUtils.sin(rotate);
    // const tan = MathUtils.tan(rotate)

    const resizeMr = () => {
      const diffWidth = dx * cos + dy * sin;
      const offsetWidth = sw + diffWidth;
      rect.w = MathUtils.stepClamp({
        value: offsetWidth,
        min: minWidth,
        max: maxWidth,
        gap: gx
      });

      if (lockAspectRatio) {
        const aspect = sw / sh;
        rect.h = Math.round(rect.w / aspect);
      }
    };
    const resizeMb = () => {
      const diffHeight = dy * cos - dx * sin;
      rect.h = MathUtils.stepClamp({
        value: sh + diffHeight,
        min: minHeight,
        max: maxHeight,
        gap: gy
      });
      if (lockAspectRatio) {
        const aspect = sw / sh;
        rect.w = Math.round(rect.h * aspect);
      }
    };
    const resizeMl = () => {
      const diffWidthLeft = dx * cos + dy * sin;
      rect.w = MathUtils.stepClamp({
        value: sw - diffWidthLeft,
        min: minWidth,
        max: maxWidth,
        gap: gx
      });
      rect.y = sy + dy * sin;
      if (w <= minWidth) {
        rect.x = sx + dx * cos;
      }

      if (lockAspectRatio) {
        const aspect = sw / sh;
        rect.h = Math.round(rect.w / aspect);
      }
    };
    const resizeMt = () => {
      const diffHeightTop = dy * cos - dx * sin;
      rect.h = MathUtils.stepClamp({
        value: sh - diffHeightTop,
        min: minHeight,
        max: maxHeight,
        gap: gy
      });
      if (lockAspectRatio) {
        const aspect = sw / sh;
        rect.w = Math.round(rect.h * aspect);
      }

      rect.x = sx + dx * sin;

      if (h <= minHeight) {
        rect.y = sy + dy * cos;
      }
    };
    const actionHandlers: {
      [key in HandleType]?: () => void;
    } = {
      /* 四边拖拽 */
      "resize-mr": resizeMr,
      "resize-mb": resizeMb,
      "resize-ml": resizeMl,
      "resize-mt": resizeMt,
      /* 对角线拖拽 */
      "resize-br": () => {
        resizeMr();
        resizeMb();
      },
      "resize-bl": () => {
        resizeMl();
        resizeMb();
      },
      "resize-tr": () => {
        resizeMr();
        resizeMt();
      },
      "resize-tl": () => {
        resizeMl();
        resizeMt();
      }
    };
    actionHandlers[key]?.();
  }
  /* 检测是否出界 */
  static detectingMovementOutOfBounds = (param: {
    rect: IDraggable;
    el: Ref<HTMLElement | null>;
    mouseRecord: MouseRecord;
    dx: number;
    dy: number;
    zoom: number;
  }) => {
    const { rect, el, mouseRecord, dx, dy, zoom } = param;
    const { vx, vy, sx, sy } = mouseRecord;
    const { grid } = rect;
    const ox = sx + dx;
    const oy = sy + dy;
    const [gx, gy] = grid;
    const [minX, minY, maxX, maxY] = MatrixUtils.calculateBounds({
      ...rect,
      x: ox,
      y: oy
    });
    const [MIN_X, MIN_Y, MAX_X, MAX_Y] = MatrixUtils.calculateBounds({
      ...rect,
      x: 0,
      y: 0
    });

    /* 开启检测 */
    if (!rect.parent) {
      rect.x = MathUtils.roundToStep(ox, gx);
      rect.y = MathUtils.roundToStep(oy, gy);
      return;
    }
    const { width: parentWidth, height: parentHeight } = DomUtils.getDomBoundary(
      el.value?.parentElement!,
      zoom
    )!;
    // 有边界场景下的分轴处理
    if (maxX > parentWidth + vx) {
      rect.x = parentWidth - MAX_X + vx;
    } else if (minX < +vx) {
      rect.x = -MIN_X + vx;
    } else {
      rect.x = MathUtils.roundToStep(ox, gx * zoom);
    }
    if (maxY > parentHeight + vy) {
      rect.y = parentHeight - MAX_Y + vy;
    } else if (minY < vy) {
      rect.y = -MIN_Y + vy;
    } else {
      rect.y = MathUtils.roundToStep(oy, gy * zoom);
    }
  };
}
